package os.homework4;

import java.util.Arrays;
import java.util.Scanner;

public class Bank {
    static int m=3;//资源数
    static int n=5;//进程数
    static int available[]=new int[m];//可利用资源向量
    static int max[][]=new int[n][m];//最大需求矩阵
    static int allocation[][]=new int[n][m];//分配矩阵
    static int need[][]=new int[n][m];//需求矩阵
    //need[][]=max[][]-allocation[][]
    static int request[]=new int[m];//请求资源向量
    static int work[]=new int[m];//工作向量，存放系统可提供的资元素数目
    static boolean finish[]=new boolean[n];//标记系统是否有足够的资源分配给进程
    static int security[]=new int[n];//存放安全序列

    public static void main(String[] args) {
        Bank bank=new Bank();
        bank.init();//初始化
        bank.request();//请求资源

    }
    //初始化T0时刻各资源矩阵
    void init(){
        //可利用资源向量，代表每类资源可利用的数目
        available=new int[]{3,3,2};
        //最大需求矩阵
        max=new int[][]{
                {7,5,3},
                {3,2,2},
                {9,0,2},
                {2,2,2},
                {4,3,3},
        };
        //分配矩阵,代表每类资源已分配给每个进程的资源数
        allocation=new int[][]{
                {0,1,0},
                {2,0,0},
                {3,0,2},
                {2,1,1},
                {0,0,2}
        };
        //需求矩阵,代表每个进程尚需的资源数\，可通过need[][]=max[][]-allocation[][]计算得到
        need=new int[][]{
                {7,4,3},
                {1,2,2},
                {6,0,0},
                {0,1,1},
                {4,3,1}
        };
    }

    /**
     * 键盘获取某进程的资源请求向量
     */
    void request(){
        Scanner scanner=new Scanner(System.in);
        int num;//进程编号
        //选择哪一个进程请求资源
        System.out.println("请选择哪一个进程请求资源，可选进程编号1-5：");
        num=scanner.nextInt()-1;
        System.out.println("确认你选择的是第"+num+"号进程,请为该进程的各资源指定请求资源数目：");
        for(int i=0;i<m;++i){
            request[i]=scanner.nextInt();
        }
        //银行家算法第一步：所申请的资源不能大于资源最大值
        boolean flag=true;
        for(int i=0;i<m;++i){
            if(request[i]>need[num][i]){
                System.err.println("所申请的资源不能大于资源最大值,申请资源失败");
                flag=false;
                return;
            } else if (request[i]>available[i]) {//可以利用的资源不足
                System.err.println("可以利用的资源不足,申请资源失败");
                flag=false;
                return;
            }
        }
        //资源可以分配，那么就试探着分配资源给num进程
        if(flag){
            probe(num);//试探分配
            showData();//查看所有的矩阵
            boolean safe=doSafe();//执行安全性算法
            if(safe!=true){
                reProbe(num);//回退试探分配
                showData();//查看所有的矩阵
            }
        }


    }

    /**
     * 回退试探分配
     * @param i
     */
    private void reProbe(int i) {
        for(int j=0;j<m;++j){
            available[j]=available[j]+request[j];
            allocation[i][j]=allocation[i][j]-request[j];
            need[i][j]=need[i][j]+request[j];
        }
    }

    /**
     * 安全算法
     * @return
     */
    private boolean doSafe() {
        int k=0;//存放安全序列的下标
        //初始化工作向量，它的初值就等于available
        work= Arrays.copyOf(available,available.length);
        //初始化finish[]，初值为false
        Arrays.fill(finish,false);
        //从进程集合中找到一个满足
        for(int i=0;i<n;++i){//进程
            int cnt=0;//统计资源数
            for(int j=0;j<m;++j){//资源
                if(finish[i]==false&&need[i][j]<=work[j]){
                    //需求量小于空闲资源量
                    cnt++;
                    if(cnt==m){
                        for(int t=0;t<m;++t){
                            work[t]=work[t]+allocation[i][t];//释放资源
                        }
                        finish[i]=true;
                        security[k++]=i;
                        i=-1;//跳出里层循环又从0开始遍历
                    }
                }
            }
        }
        for(int i=0;i<n;++i){
            System.out.println("finish["+i+"]:"+finish[i]);
        }
        for(int i=0;i<n;++i){
            if(finish[i]==false){
                System.err.println("安全算法不通过：系统不安全！！！");
                return false;
            }
        }
        System.out.println("系统安全：存在一个安全序列：");
        for (int i = 0; i < n; i++) {
            System.out.print(security[i]+"  -> ");
        }
        System.out.println();
        return true;
    }

    private void showData() {
        System.out.println("-------available空闲资源列表：-------");
        for(int i=0;i<m;++i){
            System.out.print(available[i]+" ");
        }
        System.out.println();
        System.out.println("-------allocation已分配矩阵：-------");
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                System.out.print(allocation[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println();
        System.out.println("-------need仍需要的资源矩阵：-------");
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                System.out.print(need[i][j]+" ");
            }
            System.out.println();
        }
    }

    /**
     * 试探着分配资源，主要是修改available[],allocation[][],need[][]等数据结构
     * @param i 第几号进程请求资源
     */
    private void probe(int i) {
        for(int j=0;j<m;++j){
            available[j]=available[j]-request[j];//可以用的空闲资源减少
            allocation[i][j]=allocation[i][j]+request[j];//i号进程已分配的资源增加
            need[i][j]=need[i][j]-request[j];//i号进程仍需的资源减少
        }
    }
}
